/**
** 说明：页面元数据操作模块，提供封装过的页面组件、工具函数
**/

var baseUrl = "/widget/";


(function(){
//页面元数据对象，注册到window中，全局可用

var PageMeta = function(){

	//step 1: init stage:
	this.inited = false;
	//系统中注册的扩展类型（组件），通过扩展注册类型，增加新的类型
	this.extTypes = {
			//json基础类型
			"TTextDef":null,
			"TIntegerDef":null,
			"TNumberDef":null,
			"TBooleanDef":null,
			"TArrayDef":null,
			//扩展类型
			"TRichTextDef":null,
			"TPictureDef":null,
			"TLinkDef":null,
			//自定义类型
			"TPicLinkDef":null,
			"TTextLinkDef":null,
	};

	//json schema定义的内置类型列表
	this.josnBuildInType = [ "array", "boolean", "integer", "null", "number", "object", "string" ];
};
	
PageMeta.prototype = {
		// 装载扩展类型定义
	init:function (pageMetaDefURL){
		//for(var i=0;i < this.types.length;i++){
		for(var ti in this.extTypes){ 
	    	this.initComponent(ti);
		}
		this.inited = true;
	},
	 
	//获得页面元数据的元元数据定义
	loadPageMetaMetaDef:function(pageMetaDefURL){
		var meta = fetchUrlContent(pageMetaDefURL);
		pageMeta = JSON.parse(meta);
		return transToPageModeMeta(pageMeta);
	},


	//初始化组件的meta定义，从各个组件定义json中解析
	initComponent:function(ti){
		if(this.extTypes[ti]) return this.extTypes[ti];

		var url = baseUrl + ti + ".json";
		console.log("loading widget def :" +  url);
		var tmpDef = fetchUrlContent(url);
		var clz = new window.widget(ti,tmpDef);
		clz.init();
		this.extTypes[ti] = clz; 
		return clz;
	},

	//得到制定类型的元模型定义；
	//注意：模型已经进行clone
	//array需要根据实际情况进行进一步的元素类型扩展：
	getWidgetCloneDef:function(ti,arrayObj){
		var clz = this.initComponent(ti);
		if(clz){   
			var tmp_clz = deepCopy({},clz);
			if(ti === "TArrayDef"){
				tmp_clz['title'] = arrayObj['title'];
				this.expendArrayDef(tmp_clz,arrayObj['items']);
			}
			
			if(arrayObj['options']){
				tmp_clz.metaMetaDef['options'] = deepCopy({},arrayObj['options']);
			}
			return tmp_clz;
		}
		return null;
	},

	//array需要根据实际情况进行进一步的元素类型扩展：
	expendArrayDef:function(clz,itemsDef){
		var ttp = itemsDef['type'];
		if(ttp === 'object'){
			var clz1 = buildObject(itemsDef);
			if(itemsDef['title']) clz1['title'] = itemsDef['title'];
			clz.metaMetaDef['properties']['items'] = clz1;
		}
		else{	//buildin type....
			if(this.extTypes.hasOwnProperty(ttp)){
				var clz1 = this.getWidgetCloneDef(ttp,itemsDef);
				clz.metaMetaDef['properties']['items'] = clz1.metaMetaDef; 
			}
			else{
				//
			}
		}
	},

	//判断类是否为json schema内置类型
	isJSONBuildin:function(theType){
		return this.josnBuildInType.indexOf(theType) !== -1;
	}

 
	/**	--------废弃！
	** 得到指定扩展类型的metameta定义，返回形式是json对象
	** parameter：
	**	propertyJson：原始的类型定义json，引用了扩展的类型，采用$extend机制实现内容copy
	**	extTypeName: 指定的扩展类型名字，必须在extTypes列表中
	genMeta2DefForType:function(propertyJson){	
		var extTypeName = 	propertyJson['type'];
		var typeJson = this.extTypes[extTypeName];
		if(! typeJson){
			throw "未定义的扩展类型：" + extTypeName;
		}
		propertyJson = deepCopy(propertyJson,typeJson);
		//滤除数据定义部分
		var props = propertyJson['properties'];
		for(var p in props){
			var o = props[p];
			var pt = o['type'];
			if(!this.isJSONBuildin(pt)){	//还是自定义类新型，需要递归处理
				this.genMeta2DefForType(o);
				p['type'] = "object";
			}
			else	
				if(pt === "object" && o["properties"][SCHEMA_DEF_MARK] && o["properties"][SCHEMA_DEF_MARK][SCHEMA_VLIDATION_MARK]){
					var rules = o["properties"][SCHEMA_DEF_MARK][SCHEMA_VLIDATION_MARK];
					deepCopy(o["properties"],rules);
					//delete SCHEMA_DEF_MARK node
					o["properties"][SCHEMA_DEF_MARK] = undefined;
				}
				else{
					//没有验证规则，直接忽略该属性
				};
		}
	},
	**/
	/**
	** 得到指定扩展类型的meta定义，返回形式是json对象
	** parameter：
	**	propertyJson：原始的类型定义json，引用了扩展的类型，采用$extend机制实现内容copy
	**	extTypeName: 指定的扩展类型名字，必须在extTypes列表中
	**	meta2Json:metameta最终的约束定义json，用于生成meta信息中的schema约束或扩展约束
	genMetaDefForType:function(propertyJson,extTyepName,meta2Json){

	},
	**/



} //end PageMetaObj prototype def


	//register page meta to window obj
	window.pagemeta = new PageMeta();

})();
//end closure def


/**
**	页面元数据模块共用函数库
**/
//深度copy对象函数，直接采用json-editor的js函数$extend
var deepCopy = function(destination) {
  var source, i,property;
  for(i=1; i<arguments.length; i++) {
    source = arguments[i];
    for (property in source) {
      if(!source.hasOwnProperty(property)) continue;
      if(source[property] && $isplainobject(source[property])) {
        if(!destination.hasOwnProperty(property)) destination[property] = {};
        deepCopy(destination[property], source[property]);
      }
      else {
        destination[property] = source[property];
      }
    }
  }
  return destination;
};


var $isplainobject = function( obj ) {
  // Not own constructor property must be Object
  if ( obj.constructor &&
    !obj.hasOwnProperty('constructor') &&
    !obj.constructor.prototype.hasOwnProperty('isPrototypeOf')) {
    return false;
  }

  // Own properties are enumerated firstly, so to speed up,
  // if last one is own, then all properties are own.

  var key;
  for ( key in obj ) {}

  return key === undefined || obj.hasOwnProperty(key);
};


//动态装载json数据函数，返回指定url的json字符串
function fetchUrlContent(url){
	  var r = new XMLHttpRequest();
	  var ret = ""; 
	  r.open("GET", url, false);
	  r.onreadystatechange = function () {
		console.log("url:" + url);
	    if (r.readyState != 4) return; 
	    // Request succeeded
	    if(r.status === 200) {
	      var response;
	      try {
	        ret = r.responseText;
	        return ;
	      }
	      catch(e) {
	        window.console.log(e);
	        throw "Failed to parse external ref "+url;
	      }
	     }
	    // Request failed
	    else {
	      window.console.log(r);
	      throw "Failed to fetch ref via ajax- "+url;
	    }
	  };
	  r.send();
	  return ret;
      //throw "unkown error:"+ url;
}

//对输出的页面参数定义json进行修订，修正运营层级权限的设置；
var currNodeLevel = '1'; // 当前节点的运营权限级别，默认为1：集团；
var nodeLevelStack = ['1'];
function storeParentLevel(nodeDef){
	nodeLevelStack.push(currNodeLevel);	 
	if(nodeDef['distLevel']){		
		currNodeLevel = nodeDef['distLevel'];
	}
	else{
		currNodeLevel = nodeLevelStack[0];	//set to parent level
	}
}
function restoreParentLevel(nodeDef){
	currNodeLevel = nodeLevelStack.pop();
}


var Auth4Level = function(level,parentPath){
	this.parentPath = parentPath;	//absolute path,this context's root
	// this.curPath = curPath;		//relative path(against parentPath)
	this.level = level;
	this.flatPath = [];	//relative path(against parentPath)
	this.arrayPath = [];	//new context

	this.arrayAxises = 0;
} 
//,curPath,level,parentPath,
function findAuth4Level(jsonObj,curPath,authInfo){
	if(window.isplainobject(jsonObj)) {
		//保持父级level
		storeParentLevel(jsonObj);
		// if( jsonObj['distLevel']){
			// var lvl = jsonObj['distLevel'];
			if(authInfo.level === currNodeLevel ){
				authInfo.flatPath[authInfo.flatPath.length] = curPath;
			}
		// }

		// else	//travel low level nodes
		for(var nd in jsonObj ){
			if( nd === "items") continue;
			var no = jsonObj[nd]; 
			var tp =(curPath === ""? "" : curPath +".") + nd;

			findAuth4Level(no,tp,authInfo);

			//if jsonObj is array		
			if(no['items']){	//is array def
				var pp = curPath;
				var ret = new Auth4Level(authInfo.level,tp);	//create new context
				findAuth4Level(no['items'],"",ret);
				if(ret.flatPath.length > 0 || ret.arrayPath.length > 0)
					authInfo.arrayPath[authInfo.arrayPath.length] = ret;
			}
			// else{	//is plain obj def
			// }
		}
		//恢复父级level
		restoreParentLevel(jsonObj);		
	}
}


//travel all json node
function travel(jsonObj,curPath){
	// if(!Array.isArray(jsonObj) && !window.isplainobject(jsonObj))
		// return ; //end travel
	isAuthNode(jsonObj,curPath);
	var atArrayTag = false;
	if(jsonObj["items"]){	//isarray ?? nav to items node
		arrayStack[curPath] = null;
		jsonObj = jsonObj['items'];
		curArrayPath = curPath;
		atArrayTag = true;
	}

	//for deep level travel
	if(window.isplainobject(jsonObj)){
		for(var nd in jsonObj ){
			// if(nd === "bizMeta") continue;
			var no = jsonObj[nd];
			var tp =curPath+"."+nd; 
			travel(no,tp,curArrayPath);
		}
	}
	if(Array.isArray(jsonObj)){
		var idx = 0;
		for(var no in jsonObj){
			var objIdx = no + "." + atArrayTag ? idx+"." : "";
			var tp=curPath+("."+objIdx); 
			travel(no,tp);
		}
		idx++;
	}
	if(jsonObj['items']){	//isarray ?? and out of stack scope
		arrayStack[curPath] = undefined;
	}
}


var arrayStack = {}; 
var arrayMark = ".items";
function isAuthNode(node,curPath){
	if(curPath.endsWith(arrayMark)){ //in array def scope
		var arrayPath = curPath.replace(arrayMark,"");
		var exisedArray = $("div[data-schemapath='"+arrayPath+"'][data-schematype='array']");
		if(exisedArray){
			arrayStack[arrayPath] = exisedArray;
		}
		else 
			return; //do nothing ,waiiting for array's subelement
	}
	if(curPath.indexOf(arrayMark) > -1){
		// if(arrayStack[])
	}
	if(node['distLevel']){
		var level = node['distLevel'];
		// setNodeStatus(level,curPath);
		if(level === userLevel){		//find matched level
			if(curArrayPath){	//in array stack!
				//to find 

			}
			else{
				var no = jsoneditor_cnt.getEditor(curPath);
				if(no){
					no.enable();
				}
			}
		}
	}
}

function setNodeStatus(nodeLevel,curPath){
	if(nodeLevel === userLevel){
		var no = jsoneditor_cnt.getEditor(curPath);
		if(no){
			no.enable();
		}
	}
}

/**
** 跟踪用户修改信息
**/
var changeList = {};
function eventChanged(ctrl,actionType){
	if(ctrl && ctrl.path){
		console.log("Event change:" + ctrl.path + ", actionType:"+actionType);
		changeList[ctrl.path] = actionType;
	}
	else{
		console.log("change invalided event:" + ctrl);
	}
}


///针对mcms特殊需求场景的解决方案
//1. 权限继承
/**
** 参数editor设置完毕后，扫描所有节点，对设置的运营级别和当前设置人员级别进行判断和设置：
** 1. 设置比自己运营级别高的选项为disable，不可选择
** 2. 对比自己运营级别低，但是是高运营级别的人员设置的也设置为disable
**/
function scanMeta2Level(editor,setterLevel,isSingleOp){
	var levelStack = [];
	var parentLevel = "1";
	var path = "root.pageBlocks."; 
	var curJson = editor.getValue().pageBlocks;	//页面区域定义
        if(isSingleOp){
            for(var bName  in curJson){
                    disableOpLevel(editor,curJson[bName],setterLevel,parentLevel,levelStack,path+bName);
            }
        }
        else
	for(var bName  in curJson){
		innerScanMeta2Level(editor,curJson[bName],setterLevel,parentLevel,levelStack,path+bName);
	}
}
function innerScanMeta2Level(editor,valueJson,setterLevel,parentLevel,levelStack,path){	
// 	levelStack.push(parentLevel);
	var subEditor = editor.getEditor(path);
	// 判断是否为按照数组位置授权，如果是，不再继续向下执行；
	if(subEditor && subEditor.options){
		if(subEditor.options.assignByIndex === true){
			return ;
		}
	}
	var tmpEditor = editor.getEditor(path+".distLevel");
	if(tmpEditor && tmpEditor.control.lastChild){
		var slt = tmpEditor.control.lastChild;
		var selectValue = slt.options[slt.selectedIndex].value;
		
	console.log(" scan node:" + path + ",sltval:" + selectValue +",parentLevel:" + parentLevel);
		if(selectValue === ""){ //继承父级			
			var opts = slt.options;
			for(var opt =0 ;opt < opts.length;opt++){
				if(opts[opt].value === parentLevel){
					opts[opt].selected = true;
					break;
				}
			}		
		} 
		selectValue = slt.options[slt.selectedIndex].value;
		if(selectValue < setterLevel){
			slt.disabled = true;
		}
		else{
			var opts = slt.options;
			for(var opt =0 ;opt < opts.length;opt++){
				if(opts[opt].value < setterLevel){//权限级别更高的，不能选择
					opts[opt].disabled = true;
				}
			}  
		}
	}
	//继续设置子对象
	for(var bName in valueJson){
		if(!window.isplainobject(valueJson[bName]))  continue;
		var tLevel = valueJson['distLevel'];
		if(! tLevel)  tLevel = parentLevel;
		innerScanMeta2Level(editor,valueJson[bName],setterLevel,tLevel,levelStack,path+"."+bName);	

	}
	
	// levelStack	
}

//如果为单一层级运营模式，简单的将运营权限设置为空并disabled
function disableOpLevel(editor,valueJson,setterLevel,parentLevel,levelStack,path){ 
//  levelStack.push(parentLevel);i
        var tpath = path+".distLevel";
        var slt = findOpLevelEditorByPath(editor,tpath); 
        if(slt){ 
            slt.options[0].selected = true;
            slt.disabled = true; 
         }
    //继续设置子对象
    for(var bName in valueJson){
        if(!window.isplainobject(valueJson[bName]))  continue;
        var tLevel = valueJson['distLevel'];
        if(! tLevel)  tLevel = parentLevel;
        disableOpLevel(editor,valueJson[bName],setterLevel,tLevel,levelStack,path+"."+bName);  
    }    
    // levelStack   
}


//初始化模型第一次载入的运营权限：页面区域默认设置为集团，后边的继承该设置
function initOpLevel(editor){
    var path = "root.pageBlocks."; 
    var curJson = editor.getValue().pageBlocks; //页面区域定义
    for(var bName  in curJson){
        var tpath = path+bName+".distLevel";
        var slt = findOpLevelEditorByPath(editor,tpath); 
        if(slt){
            slt.options[1].selected = true; 
        }
    }
}

///设置不同等级用户的编辑状态：
    //设置编辑状态
    function setEditor4Level(editorRoot,authInfo,ppath){
        scanArrayAxises(editorRoot,authInfo,ppath);

        var pp =  authInfo.parentPath;
        pp = ppath +  (pp === ""?"":"."+pp) ;
        for(var fp in authInfo.flatPath){
            if(authInfo.arrayAxises > 0){   //如果实例数组存在，需要在数组纬度上展开
                for(var ti =0; ti < authInfo.arrayAxises;ti++){
                    var apth = pp + "." +ti +"." + authInfo.flatPath[fp];
                    // console.log( apth);
                    var editor = editorRoot.getEditor(apth);

//             console.log("set path enable :" + preIdens +">" + parentPath + "." + authInfo.flatPath[fp]);
                    if(editor)  editor.enable();
                }
            }
            else{
                var apth = pp + "." + authInfo.flatPath[fp];
                // console.log( apth);
                var editor = editorRoot.getEditor(apth);

//             console.log("set path enable :" + preIdens +">" + parentPath + "." + authInfo.flatPath[fp]);
                if(editor)  editor.enable();
            }
        }

        var i =0;
        for(var a in authInfo.arrayPath){   //处理每个数组类型
            var ai = authInfo.arrayPath[a];
            if(authInfo.arrayAxises > 0){
                for(var ti =0 ; ti < authInfo.arrayAxises;ti ++){   //在数组类型上展开
//                     console.log(" set path: to extend@" + pp +"."+ti);
                    setEditor4Level(editorRoot,ai,pp+"."+ti);    
                }
            }
            else{
                                  console.log(" set path: to extend@" + pp);
                setEditor4Level(editorRoot,ai,pp);
            }
        }
    }

     var searchLevel = 100;

    function scanArrayAxises(editor,ai,ppath){
        var pp =  ai.parentPath;
        pp = ppath +  (pp === ""?"":"."+pp) ;
        for(var i =0; i < searchLevel;i++){
            var arrayIdxPath = pp + "." +  i;
            var arrayIns =editor.getEditor(arrayIdxPath);
            if(!arrayIns)  break;
            ai.arrayAxises = i+1;
        // console.log("scan array axis :"+ppath + ","+arrayIdxPath);
        } 
    }


//jsoneditor对象查询定位工具方法


/**
**设置整个子节点运营权限全部为某个层级,disabledSlt==true:设置控件不可修改
**/
function setOpLevelToTree(editor,path,oplevel,showTxt,disabledSlt){
	var edt = editor.getEditor(path);
	if(edt){
		var objs = edt.editors;
		for(var o in objs){
			if(o.indexOf("distLevel") > -1){
				var slt = findOpLevelEditorByPath(editor,path+"."+o);
				if(slt){
					for(var k in slt.options){
						var kk = slt.options[k];
						if(kk.value === (""+oplevel)){
							kk.selected = true;
							kk.text = showTxt;
							break;
						}
					}
					if(disabledSlt) 
						slt.disabled = true;
					else
						slt.disabled = false; 
				}
			}
			else{	//
				setOpLevelToTree(editor,path+"."+o,oplevel,showTxt,disabledSlt);
			}
		}
	}
}

//找到指定path的权限层级设置对象控件select
function findOpLevelEditorByPath(editor,path){
    var tmpEditor = editor.getEditor(path);  
        if(tmpEditor && tmpEditor.control.lastChild){
            return tmpEditor.control.lastChild;
        }
        return null;
}

//查找object数据结构对象的title html区块
//结构为：<h3><>title</><>button list</>
function getObjDefTitleArea(editor,path){
    var tdiv = editor.getEditor(path);  //ex:root.pageBlocks.A4GAd.blockTitle
    if(tdiv && tdiv.title){
        return tdiv.title; 
    }
    return null;
}
//查找obj对象属性的title定义区块;形式为：<label>xxxx</label>
function getObjPropDefTittleArea(editor,path){
    //ex:root.pageBlocks.A4GAd.blockTitle.default
    var tdiv = editor.getEditor(path);  //ex:root.pageBlocks.A4GAd.blockTitle
    if(tdiv && tdiv.label){
        return tdiv.label; 
    }
    return null;
}

//得到一个可用的按钮模版，用于后续的添加按钮等操作，
//模版来自于root对象的第一个功能按钮
var funcButtonTemp = null ;
function getTemplateButton(editor){
    if(!funcButtonTemp){
        if(!editor) return null;
        if(editor.root.title.childNodes[1].children[0]){
            funcButtonTemp = editor.root.title.childNodes[1].children[0].cloneNode();
        }
        else{
            console.error("no buttontemplate to clone");
            return null;
        }
    }

            return funcButtonTemp.cloneNode();
}
//直接得到button并设置title，callback：
//var kk = getFuncButton(jsoneditor,"你好",function(e){alert('ere');});
//ex:jsoneditor.root.title.appendChild(kk)
function getFuncButton(editor,title,callback){
    var tb = getTemplateButton(editor); 
    if(!tb) return null;

    if(title) tb.innerText = title;
    if(callback) tb.addEventListener('click',callback);
    return tb;
}



   function getFormInputField(type) {
    var el = document.createElement('input');
    el.setAttribute('type',type);
    return el;
  }